import cv2 as cv
import numpy as np


# Hough圆检测，与Hough直线检测原理类似，(x-a)^2+(y-b)^2=r^2或者x=a+rcosθ,y=b+rsinθ
# 其参数空间是三维的（即在笛卡尔的xy坐标系中经过某一点的所有圆映射到abr坐标系中就是一条三维的曲线）
def detect_circles_demo(image):
    dst = cv.pyrMeanShiftFiltering(image, 10, 100)  # 边缘保留滤波EPF（即均值漂移，详见本video/picture_blur.py）
    gray = cv.cvtColor(dst, cv.COLOR_RGB2GRAY)
    circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, 150, param1=50, param2=50, minRadius=0, maxRadius=0)
    # image参数表示8位单通道灰度输入图像矩阵。
    # method参数表示圆检测方法，目前唯一实现的方法是HOUGH_GRADIENT。
    # dp参数表示累加器与原始图像相比的分辨率的反比参数。例如，如果dp = 1，则累加器具有与输入图像相同的分辨率。如果dp=2，累加器分辨率是元素图像的一半，宽度和高度也缩减为原来的一半。
    # minDist参数表示检测到的两个圆心之间的最小距离。如果参数太小，除了真实的一个圆圈之外，可能错误地检测到多个相邻的圆圈。如果太大，可能会遗漏一些圆圈。
    # param1参数表示Canny边缘检测的高阈值，低阈值会被自动置为高阈值的一半。
    # param2参数表示圆心检测的累加阈值，参数值越小，可以检测越多的假圆圈，其值越大，对应于累加器中最大累加值的圆将首先被返回。
    # minRadius参数表示检测到的圆的最小半径。
    # maxRadius参数表示检测到的圆的最大半径。默认值为max(image_width,image_height)
    # circles参数表示检测到的圆的输出向量，向量内第一个元素是圆的横坐标，第二个是纵坐标，第三个是半径大小。
    circles = np.uint16(np.around(circles))  # 把circles包含的圆心和半径的值变成整数（np.around是一种四舍五入的函数）
    for i in circles[0, :]:
        cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)  # 画圆
        cv.circle(image, (i[0], i[1]), 2, (0, 0, 255), 2)  # 画圆心
    cv.imshow("circles", image)


src = cv.imread('imgs/test009.jpg')
cv.imshow("input_image", src)
detect_circles_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()
